package cn.xuewenbao.eduorder.service.impl;

import cn.xuewenbao.eduorder.entity.Eduorder;
import cn.xuewenbao.eduorder.entity.PayLog;
import cn.xuewenbao.eduorder.mapper.PayLogMapper;
import cn.xuewenbao.eduorder.service.EduorderService;
import cn.xuewenbao.eduorder.service.PayLogService;
import cn.xuewenbao.eduorder.utils.HttpClient;
import cn.xuewenbao.ucenter.service.VipService;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.CertAlipayRequest;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.wxpay.sdk.WXPayUtil;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * <p>
 * 支付日志表 服务实现类
 * </p>
 *
 * @author mafayu
 * @since 2021-06-30
 */
@Service
@Slf4j
public class PayLogServiceImpl extends ServiceImpl<PayLogMapper, PayLog> implements PayLogService {

    @Autowired
    private EduorderService eduorderService;
    @Autowired
    private VipService vipService;

    @Value("${alipay.app_id}")
    private String appId;

    @Value("${alipay.gateway}")
    private String gateway;

    @Value("${alipay.privateKey}")
    private String privateKey;

    @Value("${alipay.app_cert_path}")
    private String appCertPath;

    @Value("${alipay.alipay_cert_path}")
    private String alipayCertPath;

    @Value("${alipay.alipay_root_cert_path}")
    private String alipayRootCertPath;

    @Value("${alipay.alipay_pay_notify_url}")
    private String alipayPayNotifyUrl;

    //生成微信支付二维码接口
    @Override
    public Result<Map> createNatvie(String orderNo) {
        Result<Map> result = new Result<>();
        try {
            //1 根据订单号查询订单信息
            QueryWrapper<Eduorder> wrapper = new QueryWrapper<>();
            wrapper.eq("order_no", orderNo);
            Eduorder order = eduorderService.getOne(wrapper);

            //2 使用map设置生成二维码需要参数
            Map m = new HashMap();
            m.put("appid", "wx74862e0dfcf69954");
            m.put("mch_id", "1558950191");
            m.put("nonce_str", WXPayUtil.generateNonceStr());
            m.put("body", order.getContentTitle()); //课程标题
            m.put("out_trade_no", orderNo); //订单号
            m.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue() + "");
            m.put("spbill_create_ip", "127.0.0.1");
            m.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify\n");
            m.put("trade_type", "NATIVE");

            //3 发送httpclient请求，传递参数xml格式，微信支付提供的固定的地址
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
            //设置xml格式的参数
            client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
            client.setHttps(true);
            //执行post请求发送
            client.post();

            //4 得到发送请求返回结果
            //返回内容，是使用xml格式返回
            String xml = client.getContent();

            //把xml格式转换map集合，把map集合返回
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);

            //最终返回数据 的封装
            Map<String, Object> map = new HashMap<>();
            map.put("out_trade_no", orderNo);
            map.put("status", order.getStatus());
            map.put("total_fee", order.getTotalFee());
            map.put("result_code", resultMap.get("result_code"));  //返回二维码操作状态码
            map.put("code_url", resultMap.get("code_url"));        //二维码地址
            result.setResult(map);
            return result;

        } catch (Exception e) {
            throw new JeecgBootException("生成二维码失败");
        }
    }

    @Override
    public Map<String, String> queryPayStatus(String orderNo) {
        try {
            //1、封装参数
            Map m = new HashMap<>();
            m.put("appid", "wx74862e0dfcf69954");
            m.put("mch_id", "1558950191");
            m.put("out_trade_no", orderNo);
            m.put("nonce_str", WXPayUtil.generateNonceStr());

            //2 发送httpclient
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/orderquery");
            client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
            client.setHttps(true);
            client.post();

            //3 得到请求返回内容
            String xml = client.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);
            //6、转成Map再返回
            return resultMap;
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public void updateOrdersStatus(Map<String, String> map) {
        //从map获取订单号
        String orderNo = map.get("out_trade_no");
        //根据订单号查询订单信息
        QueryWrapper<Eduorder> wrapper = new QueryWrapper<>();
        wrapper.eq("order_no", orderNo);
        Eduorder order = eduorderService.getOne(wrapper);

        //更新订单表订单状态
        if (order.getStatus() == 1) {
            return;
        }
        order.setStatus(1);//1代表已经支付
        if (order.getColumnType() == null) {    //开通会员的订单
            String vipId = vipService.addVip(order.getMemberId(), order.getContentType());  //添加新的会员记录
            order.setContentId(vipId);  //设置订单所关联的会员记录的id
        }
        eduorderService.updateById(order);

        //向支付表添加支付记录
        PayLog payLog = new PayLog();
        payLog.setOrderNo(orderNo);  //订单号
        payLog.setPayTime(new Date()); //订单完成时间
        payLog.setPayType(1);//支付类型 1微信
        payLog.setTotalFee(order.getTotalFee());//总金额(分)

        payLog.setTradeState(map.get("trade_state"));//支付状态
        payLog.setTransactionId(map.get("transaction_id")); //流水号
        payLog.setAttr(JSONObject.toJSONString(map));

        baseMapper.insert(payLog);
    }

    //返回微信APP支付所需的信息，统一下单接口
    @Override
    public Result<Map> createAppPay(String orderNo, HttpServletRequest request) {
        Result<Map> result = new Result<>();
        try {
            //1 根据订单号查询订单信息
            QueryWrapper<Eduorder> wrapper = new QueryWrapper<>();
            wrapper.eq("order_no", orderNo);
            Eduorder order = eduorderService.getOne(wrapper);


            Map m = new HashMap();
            m.put("appid", "wx74862e0dfcf69954");
            m.put("mch_id", "1558950191");
            m.put("nonce_str", WXPayUtil.generateNonceStr());
            m.put("body", order.getContentTitle()); //课程标题
            m.put("out_trade_no", orderNo); //订单号
            m.put("total_fee", order.getTotalFee().multiply(new BigDecimal("100")).longValue() + "");
            m.put("spbill_create_ip", HttpClient.getIpAddress(request));
            m.put("notify_url", "http://guli.shop/api/order/weixinPay/weixinNotify\n");
            m.put("trade_type", "APP");
            //Not sure
            m.put("sign", WXPayUtil.generateSignature(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));

            //3 发送httpclient请求，传递参数xml格式，微信支付提供的固定的地址
            HttpClient client = new HttpClient("https://api.mch.weixin.qq.com/pay/unifiedorder");
            //设置xml格式的参数
            client.setXmlParam(WXPayUtil.generateSignedXml(m, "T6m9iK73b0kn9g5v426MKfHQH7X8rKwb"));
            client.setHttps(true);
            //执行post请求发送
            client.post();

            //4 得到发送请求返回结果
            //返回内容，是使用xml格式返回
            String xml = client.getContent();

            //把xml格式转换map集合，把map集合返回
            Map<String, String> resultMap = WXPayUtil.xmlToMap(xml);

            //最终返回数据 的封装
            Map<String, Object> map = new HashMap<>();
            map.put("out_trade_no", orderNo);
            map.put("status", order.getStatus());
            map.put("total_fee", order.getTotalFee());
            map.put("return_code", resultMap.get("return_code"));

            map.put("appid", resultMap.get("appid"));
            map.put("partnerId", resultMap.get("mch_id"));
            map.put("package", "Sign=WXPay");
            map.put("nonce_str", resultMap.get("nonce_str"));
            map.put("timestamp", new Date());
            //Not sure
            map.put("sign", resultMap.get("sign"));
            map.put("result_code", resultMap.get("result_code"));

            map.put("trade_type", resultMap.get("trade_type"));
            map.put("prepay_id", resultMap.get("prepay_id"));


            result.setResult(map);
            return result;

        } catch (Exception e) {
            throw new JeecgBootException("error");
        }
    }

    //返回支付宝APP支付所需的信息
    @Override
    public Result<Map> createALiPay(String orderNo) {
        Result<Map> result = new Result<>();
        Map m = new HashMap<>();

        //1 根据订单号查询订单信息
        QueryWrapper<Eduorder> wrapper = new QueryWrapper<>();
        wrapper.eq("order_no", orderNo);
        Eduorder order = eduorderService.getOne(wrapper);

        //构造client
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        //设置网关地址
        certAlipayRequest.setServerUrl(gateway);
        //设置应用Id
        certAlipayRequest.setAppId(appId);
        //设置应用私钥
        certAlipayRequest.setPrivateKey(privateKey);
        //设置请求格式，固定值json
        certAlipayRequest.setFormat("json");
        //设置字符集
        certAlipayRequest.setCharset("utf-8");
        //设置签名类型
        certAlipayRequest.setSignType("RSA2");
        //设置应用公钥证书路径
        certAlipayRequest.setCertPath(appCertPath);
        //设置支付宝公钥证书路径
        certAlipayRequest.setAlipayPublicCertPath(alipayCertPath);
        //设置支付宝根证书路径
        certAlipayRequest.setRootCertPath(alipayRootCertPath);
        //构造client
        AlipayClient alipayClient = null;
        try {
            alipayClient = new DefaultAlipayClient(certAlipayRequest);
        } catch (AlipayApiException e) {
            log.error(e.getErrMsg());
        }
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        //model.setBody(order.getContentTitle());
        model.setSubject(order.getContentTitle());
        model.setOutTradeNo(orderNo);
        model.setTimeoutExpress("30m");
        model.setTotalAmount(order.getTotalFee().toString());
        //model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        if (alipayPayNotifyUrl != null && alipayPayNotifyUrl.trim().length() > 0) {
            request.setNotifyUrl(alipayPayNotifyUrl.trim());
        }
        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            //就是orderString 可以直接给客户端请求，无需再做处理。
            m.put("orderString", response.getBody());
            result.setResult(m);
        } catch (AlipayApiException e) {
            log.error(e.getErrMsg());
        }
        return result;
    }

    @Override
    public String notifyAli(HttpServletRequest request, HttpServletResponse response) {
        //获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        //切记alipayPublicCertPath是应用公钥证书路径，请去open.alipay.com对应应用下载。
        //boolean AlipaySignature.rsaCertCheckV1(Map<String, String> params, String publicKeyCertPath, String charset,String signType)
        try {
            //调用SDK验证签名
            boolean flag = AlipaySignature.rsaCertCheckV1(params, alipayCertPath, "utf-8", "RSA2");
            log.info("验签结果:{}", flag);
            if (flag) {
                log.info("支付状态为:{}", params.get("trade_status"));
                //签名通过
                if ("TRADE_SUCCESS".equals(params.get("trade_status"))) {//支付成功
                    //付款金额
                    String amount = params.get("buyer_pay_amount");
                    //商户订单号
                    String out_trade_no = params.get("out_trade_no");
                    //支付宝交易号
                    String trade_no = params.get("trade_no");
                    //公用参数（附加数据）
                    String passback_params = params.get("passback_params");
                    String responseJson = JSONObject.toJSONString(params);

                    QueryWrapper<PayLog> logWrapper =  new QueryWrapper<>();
                    logWrapper.eq("order_no", out_trade_no);
                    PayLog log = baseMapper.selectOne(logWrapper);
                    //已经修改订单状态
                    if (log != null) {  //已生成支付日志
                        return "success";
                    }
                    //未修改订单状态
                    insertPayLogAndUpdateOrder(params.get("trade_status"), amount, out_trade_no, trade_no, responseJson, 2);
                }
            } else {
                log.info("==================验签失败 ！");
                return "failure";
            }
        } catch (AlipayApiException e) {
            log.info("==================验签失败 ！");
            log.error(e.getErrMsg());
            return "failure";
        }
        return "success";
    }


    //查询支付宝订单状态
    @Override
    public Result<Eduorder> queryAliPayStatus(String orderNo) {
        Result<Eduorder> result = new Result<>();

        //
        //构造client
        CertAlipayRequest certAlipayRequest = new CertAlipayRequest();
        //设置网关地址
        certAlipayRequest.setServerUrl(gateway);
        //设置应用Id
        certAlipayRequest.setAppId(appId);
        //设置应用私钥
        certAlipayRequest.setPrivateKey(privateKey);
        //设置请求格式，固定值json
        certAlipayRequest.setFormat("json");
        //设置字符集
        certAlipayRequest.setCharset("utf-8");
        //设置签名类型
        certAlipayRequest.setSignType("RSA2");
        //设置应用公钥证书路径
        certAlipayRequest.setCertPath(appCertPath);
        //设置支付宝公钥证书路径
        certAlipayRequest.setAlipayPublicCertPath(alipayCertPath);
        //设置支付宝根证书路径
        certAlipayRequest.setRootCertPath(alipayRootCertPath);
        //构造client
        AlipayClient alipayClient = null;
        try {
            alipayClient = new DefaultAlipayClient(certAlipayRequest);
        } catch (AlipayApiException e) {
            log.error(e.getErrMsg());
        }

//        AlipayClient alipayClient = new DefaultAlipayClient(gateway, appId, privateKey, "json", "utf-8");
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(orderNo);
        request.setBizModel(model);
        AlipayTradeQueryResponse response = null;
        try {
            response = alipayClient.certificateExecute(request);
            final val tradeStatus = response.getTradeStatus();
            if (tradeStatus.equals("TRADE_SUCCESS")) {
                //交易成功
                //付款金额
                String amount = response.getTotalAmount();
                //商户订单号
                String out_trade_no = response.getOutTradeNo();
                //支付宝交易号
                String trade_no = response.getTradeNo();
                String responseJson =  JSONObject.toJSONString(response);
                //查询payLog是否已经插入
                QueryWrapper<PayLog> logWrapper =  new QueryWrapper<>();
                logWrapper.eq("order_no", out_trade_no);
                PayLog log = baseMapper.selectOne(logWrapper);
                //已经修改订单状态, 直接返回订单
                if (log != null) {  //已生成支付日志
                    QueryWrapper<Eduorder> wrapper = new QueryWrapper<>();
                    wrapper.eq("order_no", out_trade_no);
                    Eduorder order = eduorderService.getOne(wrapper);
                    if ("TRADE_SUCCESS".equals(log.getTradeState())) {
                        return Result.OK("支付成功", order);
                    } else {
                        return Result.OK("支付失败", order);
                    }
                }
                //未修改订单状态
                Eduorder order = insertPayLogAndUpdateOrder(tradeStatus, amount, out_trade_no, trade_no, responseJson, 2);
                result.setSuccess(true);
                result.setMessage("支付成功");
                result.setResult(order);
                return result;
            } else {
                result.setSuccess(false);
                result.setMessage("支付失败");
                return result;
            }
        } catch (AlipayApiException e) {
            log.error(e.getErrMsg());
            result.setSuccess(false);
            result.setMessage("查询支付结果异常");
            return result;
        }
    }


    private Eduorder insertPayLogAndUpdateOrder(String tradeStatus, String amount, String out_trade_no, String trade_no, String responseJson, Integer payType) {
        //向支付表添加支付记录
        PayLog payLog = new PayLog();
        payLog.setOrderNo(out_trade_no);  //订单号
        payLog.setPayTime(new Date()); //订单完成时间
        payLog.setPayType(payType);//支付类型 1微信, 2支付宝
        payLog.setTotalFee(new BigDecimal(amount));//总金额(元)

        payLog.setTradeState(tradeStatus);//支付状态
        payLog.setTransactionId(trade_no); //流水号
        payLog.setAttr(responseJson);

        baseMapper.insert(payLog);
        QueryWrapper<Eduorder> wrapper = new QueryWrapper<>();
        wrapper.eq("order_no", out_trade_no);
        Eduorder order = eduorderService.getOne(wrapper);
        order.setStatus(1);
        order.setPayType(payType);
        if (order.getColumnType() == null) {    //开通会员的订单
            String vipId = vipService.addVip(order.getMemberId(), order.getContentType());  //添加新的会员记录
            order.setContentId(vipId);  //设置订单所关联的会员记录的id
        }
        eduorderService.updateById(order);
        return order;
    }
}
